package com.hex.ds.hdrs.common.excel;

import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import cn.hutool.core.util.StrUtil;
import com.hex.bigdata.hbda.utils.StringUtils;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.enums.ExcelImportOperationEnum;
import com.hex.ds.hdrs.common.enums.JobPeriodEnum;
import com.hex.ds.hdrs.period.job.dto.PeriodJobTaskDto;
import com.hex.ds.hdrs.period.job.po.PeriodJobDef;
import com.hex.ds.hdrs.period.job.service.PeriodJobDefService;
import com.hex.ds.hdrs.period.task.po.PeriodTaskDef;
import com.hex.ds.hdrs.period.task.service.PeriodTaskDefService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * @Package: com.hex.ds.hdrs.common.excel
 * @ClassName TalentImportVerifyHandler
 * @Description: 周期作业定义导入自定义校验
 * @Author: ji.tang
 * @Date 2023/2/28 11:08
 * @Version v1.0
 **/
@Data
@Component
public class CycleTaskImportVerifyHandler implements IExcelVerifyHandler<PeriodJobTaskDto> {

    public String appCode;

    @Autowired
    private PeriodJobDefService periodJobDefService;

    @Autowired
    private PeriodTaskDefService periodTaskDefService;

    private final ThreadLocal<List<PeriodJobTaskDto>> threadLocal = new ThreadLocal<>();

    /**
     * @Method: verifyHandler
     * @Param: [pj]
     * @Return: cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult
     * @Description: 导入校验
     * @Author: ji.tang
     * @Date: 2023/2/28 11:27
     * @Version: V1.0
     */
    @Override
    public ExcelVerifyHandlerResult verifyHandler(PeriodJobTaskDto periodJobTaskDto) {
        List<PeriodJobTaskDto> threadLocalVal = threadLocal.get();
        if (threadLocalVal == null) {
            threadLocalVal = new ArrayList<>();
        }
        StringJoiner joiner = new StringJoiner(",");
        if (StrUtil.isNotBlank(periodJobTaskDto.getJobCode()) && StrUtil.isNotBlank(periodJobTaskDto.getTaskCode())){
            //作业编码校验
            checkJobCode(joiner, periodJobTaskDto);
            //任务编码校验
            checkTaskCode(joiner, periodJobTaskDto, threadLocalVal);
            //调度间隔校验
            checkJobPeriod(joiner, periodJobTaskDto);
            //业务日期校验
            checkBizDate(joiner, periodJobTaskDto);
            //校验依赖作业
//            checkDependJob(joiner, periodJobTaskDto, threadLocalVal);
            //校验依赖任务
//            checkDependTask(joiner, periodJobTaskDto, threadLocalVal);
            // 检验有限时间段
            checkIsValidDate(joiner, periodJobTaskDto);

            threadLocalVal.add(periodJobTaskDto);
            threadLocal.set(threadLocalVal);
            if (joiner.length() != 0) {
                return new ExcelVerifyHandlerResult(false, joiner.toString());
            }
        }
        return new ExcelVerifyHandlerResult(true);
    }


    /*
     * @Method: checkJobCode <br>
     * @Param: [joiner, periodJobTaskDto] <br>
     * @Return: void <br>
     * @Description：判断周期作业编码是否存在<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/24 14:59 <br>
     * @Version： V2.0.2<br>
     */
    public void checkJobCode(StringJoiner joiner, PeriodJobTaskDto periodJobTaskDto) {
        PeriodJobDef periodJobDef = periodJobDefService.getJobDefByJobCode(periodJobTaskDto.getJobCode());
        if (periodJobDef != null && !periodJobDef.getAppCode().equals(appCode)){
            joiner.add("[作业编码]" + periodJobTaskDto.getJobCode() + "已存在且不属于当前应用");
        }else if (ExcelImportOperationEnum.A.getName().equals(periodJobTaskDto.getOperation()) && periodJobDef != null) {
            joiner.add("[作业编码]" + periodJobTaskDto.getJobCode() + "已存在，不允许重复新增");
        } else if ((ExcelImportOperationEnum.U.getName().equals(periodJobTaskDto.getOperation())
                || ExcelImportOperationEnum.D.getName().equals(periodJobTaskDto.getOperation())) && periodJobDef == null) {
            joiner.add("[作业编码]" + periodJobTaskDto.getJobCode() + "不存在，不能更新或删除");
        }
    }

    /**
     * @Method: checkTaskCode
     * @Param: [taskCode, dbCycleTaskMap, taskCodeList, operator]
     * @Return: java.lang.String
     * @Description: 任务编码校验
     * @Author: ji.tang
     * @Date: 2023/2/28 14:39
     * @Version: V1.0
     */
    public void checkTaskCode(StringJoiner joiner, PeriodJobTaskDto periodJobTaskDto, List<PeriodJobTaskDto> threadLocalVal) {
        for (PeriodJobTaskDto haveCheckDto : threadLocalVal) {
            if (haveCheckDto.getTaskCode().equals(periodJobTaskDto.getTaskCode())) {
                joiner.add("[任务编码]" + periodJobTaskDto.getTaskCode() + "与第" + (haveCheckDto.getRowNum() + 1) + "行数据重复");
            }
        }
        PeriodTaskDef periodTaskDef = periodTaskDefService.qryPeriodTaskDef(periodJobTaskDto.getTaskCode());
        if (periodTaskDef != null && !periodTaskDef.getAppCode().equals(appCode)){
            joiner.add("[任务编码]" + periodJobTaskDto.getJobCode() + "已存在且不属于当前应用");
        }else if (ExcelImportOperationEnum.A.getName().equals(periodJobTaskDto.getOperation()) && periodTaskDef != null) {
            joiner.add("[任务编码]" + periodJobTaskDto.getTaskCode() + "已存在，不允许重复添加");
        } else if ((ExcelImportOperationEnum.U.getName().equals(periodJobTaskDto.getOperation())
                || ExcelImportOperationEnum.D.getName().equals(periodJobTaskDto.getOperation())) && periodTaskDef == null) {
            joiner.add("[任务编码]" + periodJobTaskDto.getTaskCode() + "不存在，不允许更新或删除");
        }
    }

    /**
     * @Method: checkDateExpression
     * @Param: [isSingleJob, dateExpression]
     * @Return: java.lang.String
     * @Description: 调度间隔校验
     * @Author: ji.tang
     * @Date: 2023/2/28 14:38
     * @Version: V1.0
     */
    public void checkJobPeriod(StringJoiner joiner, PeriodJobTaskDto periodJobTaskDto) {
        if (Const.NOT_SINGLE_JOB.equals(periodJobTaskDto.getIsSingleJob())) {
            String jobPeriod = getJobPeriod(periodJobTaskDto); // 调度间隔
            String dateExpression = getDateExpression(periodJobTaskDto); // 日期表达式
            if (jobPeriod.equals(JobPeriodEnum.D.getName()) || jobPeriod.equals(JobPeriodEnum.D.getValue())) {
                checkDay(joiner, periodJobTaskDto.getJobPeriod());
            } else if (StrUtil.isBlank(dateExpression) || !StrUtil.startWith(dateExpression, "[") || !StrUtil.endWith(dateExpression, "]")) {
                joiner.add("[调度间隔]格式不正确，调度间隔除D或日外，其他调度间隔的日期表达式需要用[]包括，比如每月月末的调度间隔设置为M[-1]或月[-1]");
            } else {
                checkDateExpression(joiner, dateExpression, jobPeriod);
            }
        }
    }

    /*
     * @Method: getJobPeriod <br>
     * @Param: [periodJobTaskDto] <br>
     * @Return: java.lang.String <br>
     * @Description：获取调度间隔<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 11:52 <br>
     * @Version： V2.0.2<br>
     */
    private String getJobPeriod(PeriodJobTaskDto periodJobTaskDto){
        String jobPeriod = periodJobTaskDto.getJobPeriod().substring(0, 1);
        if (periodJobTaskDto.getJobPeriod().startsWith(JobPeriodEnum.O.getValue())){
            jobPeriod = periodJobTaskDto.getJobPeriod().substring(0, 3);
        }
        return jobPeriod;
    }

    /*
     * @Method: getDateExpression <br>
     * @Param: [periodJobTaskDto] <br>
     * @Return: java.lang.String <br>
     * @Description：获取作业日期表达式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 11:54 <br>
     * @Version： V2.0.2<br>
     */
    private String getDateExpression(PeriodJobTaskDto periodJobTaskDto){
        String dateExpression = periodJobTaskDto.getJobPeriod().substring(1);
        if (periodJobTaskDto.getJobPeriod().startsWith(JobPeriodEnum.O.getValue())){
            dateExpression = periodJobTaskDto.getJobPeriod().substring(3);
        }
        return dateExpression;
    }

    /*
     * @Method: checkDateExpression <br>
     * @Param: [joiner, dateExpression, jobPeriod] <br>
     * @Return: void <br>
     * @Description：验证调度间隔的格式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 12:00 <br>
     * @Version： V2.0.2<br>
     */
    private void checkDateExpression(StringJoiner joiner, String dateExpression, String jobPeriod) {
        dateExpression = StrUtil.removeSuffix(StrUtil.removePrefix(dateExpression, "["), "]");
        if ((jobPeriod.equals(JobPeriodEnum.W.getName()) || jobPeriod.equals(JobPeriodEnum.W.getValue()))) {
            checkWeek(joiner, dateExpression);
        } else if (jobPeriod.equals(JobPeriodEnum.M.getName()) || jobPeriod.equals(JobPeriodEnum.M.getValue())) {
            checkMonth(joiner, dateExpression);
        } else if (jobPeriod.equals(JobPeriodEnum.Q.getName()) || jobPeriod.equals(JobPeriodEnum.Q.getValue())) {
            checkQuarter(joiner, dateExpression);
        } else if (jobPeriod.equals(JobPeriodEnum.Y.getName()) || jobPeriod.equals(JobPeriodEnum.Y.getValue())) {
            checkYear(joiner, dateExpression);
        } else if (jobPeriod.equals(JobPeriodEnum.O.getName()) || jobPeriod.equals(JobPeriodEnum.O.getValue())) {
            checkCustom(joiner, dateExpression);
        } else {
            joiner.add("[调度间隔]格式不正确，只支持D、日、W、周、M、月、Q、季、Y、年、O、自定义");
        }
    }

    /*
     * @Method: checkDay <br>
     * @Param: [joiner, jobPeriod] <br>
     * @Return: void <br>
     * @Description：验证调度间隔为天的格式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 12:00 <br>
     * @Version： V2.0.2<br>
     */
    private void checkDay(StringJoiner joiner, String jobPeriod) {
        if (jobPeriod.length() > 1)
            joiner.add("[调度间隔]格式不正确，调度间隔为D或日时，只能输入这两个字符");
    }

    /*
     * @Method: checkWeek <br>
     * @Param: [joiner, dateExpression] <br>
     * @Return: void <br>
     * @Description：验证调度间隔为周的格式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 12:00 <br>
     * @Version： V2.0.2<br>
     */
    private void checkWeek(StringJoiner joiner, String dateExpression){
        if (StrUtil.isBlank(dateExpression) || !checkInteger(dateExpression) || (Integer.valueOf(dateExpression) < 0 || Integer.valueOf(dateExpression) > 6))
            joiner.add("[调度间隔]格式不正确，调度间隔为W或周时，[]中的数值为大于等于0，小于等于6");
    }

    /*
     * @Method: checkMonth <br>
     * @Param: [joiner, dateExpression] <br>
     * @Return: void <br>
     * @Description：验证调度间隔为月的格式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 11:59 <br>
     * @Version： V2.0.2<br>
     */
    private void checkMonth(StringJoiner joiner, String dateExpression){
        if (StrUtil.isBlank(dateExpression) || !checkInteger(dateExpression) || (Integer.valueOf(dateExpression) < -30 || Integer.valueOf(dateExpression) > 30))
            joiner.add("[调度间隔]格式不正确，调度间隔为M或月时，[]中的数值为大于等于-30，小于等于30");
    }

    /*
     * @Method: checkQuarter <br>
     * @Param: [joiner, dateExpression] <br>
     * @Return: void <br>
     * @Description：验证调度间隔为季的格式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 11:59 <br>
     * @Version： V2.0.2<br>
     */
    private void checkQuarter(StringJoiner joiner, String dateExpression){
        if (StrUtil.isBlank(dateExpression) || !checkInteger(dateExpression) || (Integer.valueOf(dateExpression) < -30 || Integer.valueOf(dateExpression) > 30))
            joiner.add("[调度间隔]格式不正确，调度间隔为Q或季时，[]中的数值为大于等于-30，小于等于30");
    }

    /*
     * @Method: checkYear <br>
     * @Param: [joiner, dateExpression] <br>
     * @Return: void <br>
     * @Description：验证调度间隔为年的格式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 11:59 <br>
     * @Version： V2.0.2<br>
     */
    private void checkYear(StringJoiner joiner, String dateExpression){
        if (StrUtil.isBlank(dateExpression) || !checkInteger(dateExpression) || (Integer.valueOf(dateExpression) < -365 || Integer.valueOf(dateExpression) > 365))
            joiner.add("[调度间隔]格式不正确，调度间隔为Y或年时，[]中的数值为大于等于-365，小于等于365");
    }

    /*
     * @Method: checkInteger <br>
     * @Param: [dateExpression] <br>
     * @Return: boolean <br>
     * @Description：判断日期表达式是否是整数<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/24 17:32 <br>
     * @Version： V2.0.2<br>
     */
    private boolean checkInteger(String dateExpression) {
        try {
            Integer.valueOf(dateExpression);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /*
     * @Method: checkCustom <br>
     * @Param: [joiner, dateExpression] <br>
     * @Return: void <br>
     * @Description：验证自定义格式<br>
     * @Author： wz.li<br>
     * @Date： 2023/3/27 11:59 <br>
     * @Version： V2.0.2<br>
     */
    private void checkCustom(StringJoiner joiner, String dateExpression) {
        String[] dateExpressions = dateExpression.split(" ");
        if (dateExpressions.length != 3) {
            joiner.add("[调度间隔]格式不正确，调度间隔为O或自定义时，[]中的数值为空格分割的年 月 日");
        }

    }

    /**
     * @Method: checkBizDate
     * @Param: [isSingleJob, bizDate]
     * @Return: java.lang.String
     * @Description: 业务日期校验
     * @Author: ji.tang
     * @Date: 2023/2/28 14:38
     * @Version: V1.0
     */
    public void checkBizDate(StringJoiner joiner, PeriodJobTaskDto periodJobTaskDto) {
        if (Const.IS_SINGLE_JOB.equals(periodJobTaskDto.getIsSingleJob()) && StringUtils.isBlank(periodJobTaskDto.getBizDate())) {
            joiner.add("[业务日期]单次作业业务日期不允许为空");
        }
    }

    /**
     * @Method: checkDependJob
     * @Param: [dependJob, taskCode]
     * @Return: java.lang.String
     * @Description: 依赖作业校验
     * @Author: ji.tang
     * @Date: 2023/2/28 14:38
     * @Version: V1.0
     */
    public void checkDependJob(StringJoiner joiner, PeriodJobTaskDto periodJobTaskDto, List<PeriodJobTaskDto> threadLocalVal) {
        if (StringUtils.isNotBlank(periodJobTaskDto.getDependJob())) {
            List<String> jobCodeList = threadLocalVal.stream().map(PeriodJobTaskDto::getJobCode).distinct().collect(Collectors.toList());
            String[] dependJobs = periodJobTaskDto.getDependJob().split(",");
            for (int i = 0; i < dependJobs.length; i++) {
                PeriodJobDef periodJobDef = periodJobDefService.getJobDefByJobCode(dependJobs[i]);
                if (null == periodJobDef && !jobCodeList.contains(dependJobs[i])) {
                    joiner.add("[依赖作业]上游依赖作业：" + dependJobs[i] + "不存在");
                }
            }
        }
    }

    /**
     * @Method: checkDependTask
     * @Param: [dependTask, taskCode]
     * @Return: java.lang.String
     * @Description: 依赖任务校验
     * @Author: ji.tang
     * @Date: 2023/2/28 14:37
     * @Version: V1.0
     */
    public void checkDependTask(StringJoiner joiner, PeriodJobTaskDto periodJobTaskDto, List<PeriodJobTaskDto> threadLocalVal) {
        if (StringUtils.isNotBlank(periodJobTaskDto.getDependTask())) {
            List<String> taskCodeList = threadLocalVal.stream().map(PeriodJobTaskDto::getTaskCode).distinct().collect(Collectors.toList());
            String[] dependTasks = periodJobTaskDto.getDependTask().split(",");
            for (int i = 0; i < dependTasks.length; i++) {
                PeriodTaskDef periodTaskDef = periodTaskDefService.qryPeriodTaskDef(dependTasks[i]);
                if (periodTaskDef == null && !taskCodeList.contains(dependTasks[i])) {
                    joiner.add("[依赖任务]上游依赖任务:" + dependTasks[i] + "不存在");
                }
            }
        }
    }

    /**
     * @Method: checkStartDate
     * @Param: [isValidDate, startDate]
     * @Return: java.lang.String
     * @Description: 开始时间校验
     * @Author: ji.tang
     * @Date: 2023/2/28 14:37
     * @Version: V1.0
     */
    public void checkIsValidDate(StringJoiner joiner, PeriodJobTaskDto periodJobTaskDto) {
        if ("1".equals(periodJobTaskDto.getIsValidDate()) &&
                (StringUtils.isBlank(periodJobTaskDto.getJobStDate()) || StringUtils.isBlank(periodJobTaskDto.getJobEndDate()))) {
            joiner.add("[有效时间段]该作业开启了有效时间限制，但开始时间或结束时间为空");
        }
    }

}
